/**
 * 此文件负责系统权限模块具体实现
 *
 * 设计思路：
 * 系统中权限分为三层： 一级菜单权限->二级菜单权限->页面功能项权限
 * 为保证各个模块需要检查一个（菜单/功能按钮）权限时，可以以尽可能简单和统一的方式去鉴权，减少权限对实际业务的侵入性，和充分利用ts代码提示
 * 没有直接使用从服务端获取的数据结构，而是前端构建一个权限机制，权限模块消费者统一从checkPermission函数获得 菜单/功能组件 的授权状况
 *
 * @author wujianx
 * @createTime 2020-10-20
 */
import { getStore } from 'store/store';
import { PermissionItem, PermissionType } from '../admin/schema/PermissionTypes';
import { getMenuPermission, getRolePermission } from '../admin/servers/servers';
/**
 * 权限管理类
 * 职责：
 * 1. 从服务端获取角色权限
 * 2. 通知外界角色权限列表已加载完毕
 * 3. 对外暴露角色权限信息
 */
export class PermissionMgr {
  private reqPromise: Promise<void>;
  private permissionList: PermissionItem[] = [];
  /**:存在roleId，则获取角色权限；不存在roleId，则获取菜单权限 */
  private roleId?: number;
  // permissionList的扁平化数组，构造此数组方便快捷查询某权限的信息，而避免从permissionList中去递归寻找
  private flattenArr: PermissionItem[];
  constructor(roleId?: number) {
    this.roleId = roleId || undefined;
    this.flattenArr = [];
    this.reqPromise = new Promise(resolve => resolve());
    this.fetchPermission()
      .then(() => this.buildFlatten())
      .catch(error => {
        console.log('权限获取失败', error);
      });
  }
  /**
   * 获取权限信息
   */
  private fetchPermission(): Promise<void> {
    return (this.reqPromise = new Promise((resolve, reject) => {
      if (this.roleId) {
        // 根据角色获取权限
        getRolePermission(this.roleId).then(permission => {
          this.permissionList = permission.data || [];
          resolve();
        });
      } else {
        // 获取菜单权限
        getMenuPermission()
          .then(permission => {
            this.permissionList = permission.data || [];
            // TODO前端mock菜单***一级菜单权限，上线需注释
            // this.permissionList.push({
            //   permissionId: 0,
            //   permissionTitle: '/enterpriseBill',
            //   list: null,
            // } as any);
            console.log(this.permissionList, '权限列表');
            // 存储一级菜单，方便折叠展开
            const menus: string[] = [];
            // eslint-disable-next-line array-callback-return
            this.permissionList.map((item: any) => {
              // 前端mock菜单***二级菜单权限，上线需注释
              // if (item.permissionTitle === '/webMonitor') {
              //   item.list.push({ permissionTitle: '/webMonitor/seatMonitor' });
              // }
              // 增加前缀类型：默认增加webapp，坐席端：增加webseats
              if (item.permissionTitle === '/seats') {
                menus.push('/webseats' + item.permissionTitle);
              } else {
                menus.push('/webapp' + item.permissionTitle);
              }
            });
            console.log(menus, '有权限的所有一级菜单path');
            const store = getStore();
            store.set('level1Menus', menus);
            store.save();
            resolve();
          })
          .catch(() => {
            reject();
          });
      }
    }));
  }

  /**
   * 刷新权限信息
   */
  public refreshPermission(): Promise<PermissionItem[]> {
    return new Promise((resolve, reject) => {
      console.log('刷新权限-refreshPermission');
      if (this.roleId) {
        getRolePermission(this.roleId)
          .then(permission => {
            const permissionList = (this.permissionList = permission.data || []);
            resolve(permissionList);
          })
          .catch(() => {
            reject();
          });
      } else {
        getMenuPermission()
          .then(permission => {
            const permissionList = (this.permissionList = permission.data || []);
            resolve(permissionList);
          })
          .catch(() => {
            reject();
          });
      }
    });
  }
  /**
   * 扁平化权限组
   */
  private buildFlatten(): void {
    const arr: PermissionItem[] = [];
    const deepGet = (item: PermissionItem) => {
      arr.push({
        permissionId: item.permissionId,
        permissionTitle: item.permissionTitle,
        idParent: item.idParent,
      });
      if (item.list) {
        item.list.forEach(li => {
          deepGet(li);
        });
      }
    };
    this.permissionList.forEach(permissionItem => {
      deepGet(permissionItem);
    });
    this.flattenArr = arr;
  }
  /**
   * 等待权限获取完毕
   */
  public waitFetchPermission(): Promise<void> {
    return this.reqPromise;
  }

  /**
   * 根据id或permissionType来获取一项权限
   */
  public getPermissionItem(option: { id?: number; type?: PermissionType }): PermissionItem {
    const { flattenArr } = this;
    const { id, type } = option;
    if (id != null) {
      return flattenArr.find(item => item.permissionId === id) as PermissionItem;
    }
    if (type != null) {
      return flattenArr.find(item => item.permissionTitle === type) as PermissionItem;
    }
    return {} as PermissionItem;
  }
  /**
   * 查询权限对应的permissionId
   * 返回-1说明查询的此项权限未被授权
   */
  public getPermissionId(type: PermissionType): number {
    const aim = this.getPermissionItem({ type: type });
    if (!aim) {
      return -1;
    }
    return aim.permissionId;
  }

  /**
   * 获得所有权限组
   */
  public getValue(): PermissionItem[] {
    return this.permissionList;
  }
}
/**
 * PermissionMgr的全局单例
 */
let menuPermissionMgr: PermissionMgr;
/**
 * 菜单权限
 * 获得permissionMgr单例的唯一方式
 * 获取现有的permissionMgr或是初始化后再返回
 */
export const getMenuPermissionMgr = (): PermissionMgr => {
  if (menuPermissionMgr) {
    return menuPermissionMgr;
  }
  // 创建菜单权限实例
  buildMenuPermissionMgr();
  return menuPermissionMgr;
};
/**
 * 创建permissionMgr实例
 */
export const buildMenuPermissionMgr = (): void => {
  console.log('创建菜单权限实例');
  menuPermissionMgr = new PermissionMgr();
};
/**
 * 权限检查函数，通过此函数判断某一模块是否被授权
 * 权限获取本身是一个异步操作（需要从后端获取权限），为了减少权限模块对其他业务的侵入性，
 * 此方法只在permissionMgr.waitFetchPermission执行后才调用，函数消费者就能使用同步写法来查询权限
 */
export const checkPermission = (type: PermissionType): boolean => {
  /**
   * 前端会被部署到服务端下，前端路由统一新增“/webapp”前缀，检查菜单路径时替换一次以沿用以前的流程逻辑
   * type为不带前缀的path
   */
  // type = type.replace('/webapp', '').replace('/webseats', '') as PermissionType;
  // return getMenuPermissionMgr().getPermissionId(type) > -1 ? true : false;
  return true;
};
